package com.gkzf.ai.module.crm.service.creditReport;

import cn.hutool.core.date.DateUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gkzf.ai.framework.common.exception.ServerException;
import com.gkzf.ai.module.crm.dal.dataobject.creditReport.CreditReportBasicDO;
import com.gkzf.ai.module.crm.dal.dataobject.creditReport.CreditReportDO;
import com.gkzf.ai.module.crm.dal.mysql.creditReport.CreditReportMapper;
import com.gkzf.ai.module.crm.enums.ModelAnalysisDictEnum;
import com.gkzf.ai.module.crm.threads.CreditReportThreadsPost;
import com.gkzf.ai.module.system.api.dict.DictDataApi;
import com.gkzf.ai.module.system.api.dict.dto.DictDataRespDTO;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.gkzf.ai.module.crm.util.assembly.AssemblyCreditReportDetails.*;
import static com.gkzf.ai.module.crm.util.simpleCredit.SimpleCreditExtract.RESULT;

/**
 * CRM 征信报告 Service 实现类
 *
 * @author 国科智飞
 */
@Service
@Slf4j
public class CreditReportServiceImpl implements CreditReportService {
    @Resource
    private DictDataApi dictDataApi;
    @Resource
    private CreditReportAdmittanceConditionService creditReportAdmittanceConditionService;

    @Resource
    private CreditReportMapper creditReportMapper;

    @Override
    public CreditReportBasicDO createCreditReport(CreditReportBasicDO creditReportBasicDO,CreditReportDO creditReportDO,String channelType) throws Exception {
        // 3 可能出现报错问题 配置RetryTemplate 提供了编程式重试的 API
        RetryTemplate retryTemplate = new RetryTemplate();
        // 4 设置重试策略 最大重试 3 次，只重试 RuntimeException
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3, Collections.singletonMap(ServerException.class, true));
        retryTemplate.setRetryPolicy(retryPolicy);
        creditReportDO.setCreditBasicId(creditReportBasicDO.getId());
        // 5 设置退避策略
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        // 延迟 1 秒
        backOffPolicy.setBackOffPeriod(1000);
        retryTemplate.setBackOffPolicy(backOffPolicy);
        // 大模型贷款分析v2
        DictDataRespDTO modelAnalysisCalculationLoanV2 = dictDataApi.parseDictData(ModelAnalysisDictEnum.DICT_TYPT.getCode(), ModelAnalysisDictEnum.LOAN_V2.getCode());
        // 大模型信用卡分析v2
        DictDataRespDTO modelAnalysisCalculationCreditCardV2 = dictDataApi.parseDictData(ModelAnalysisDictEnum.DICT_TYPT.getCode(),ModelAnalysisDictEnum.CREDIT_CARD_V2.getCode());

        // 大模型贷款分析v2
        DictDataRespDTO modelAnalysisCalculationQueryV2 = dictDataApi.parseDictData(ModelAnalysisDictEnum.DICT_TYPT.getCode(),ModelAnalysisDictEnum.QUERY_V2.getCode());
        // 大模型信用卡分析v2
        DictDataRespDTO modelAnalysisCalculationBasicV2 = dictDataApi.parseDictData(ModelAnalysisDictEnum.DICT_TYPT.getCode(),ModelAnalysisDictEnum.BASIC_V2.getCode());
        // 请求5次
        Map<String, String> storageMap = new HashMap<>();
        Map<String, Object> reqMap = retryTemplate.execute(context -> {
            ExecutorService executor = Executors.newFixedThreadPool(8);
            Map<String, Object> map = null;
            try {
                map = createCreditReport(modelAnalysisCalculationQueryV2,
                        modelAnalysisCalculationLoanV2,
                        modelAnalysisCalculationCreditCardV2,
                        modelAnalysisCalculationBasicV2,
                        creditReportBasicDO.getCreditReportUrl(),
                        creditReportDO,
                        storageMap,
                        executor);
                map.forEach((key, value) -> {
                    ObjectMapper objectMapper = new ObjectMapper();
                    try {
                        JsonNode jsonNode = objectMapper.readTree(value.toString());
                        JsonNode result = jsonNode.get(RESULT);
                        if (null == result){
                            throw new ServerException(-1,"正在处理中，请稍后重试");
                        }
                        storageMap.put(key,"1");
                    } catch (JsonProcessingException e) {
                        throw new ServerException(-1,"正在处理中，请稍后重试");
                    }
                });
            }catch (Exception e){
                throw new ServerException(-1,"正在处理中，请稍后重试");
            }finally {
                executor.shutdown(); //  必须关闭，否则程序不会退出
            }
            storageMap.clear();
            return map;
        });
        creditReportAdmittanceConditionService.createCreditReportAdmittanceCondition(reqMap,creditReportBasicDO,channelType);

        return creditReportBasicDO;
    }

    @Override
    public void createCreditReport(CreditReportDO creditReportDO) {
        creditReportMapper.insert(creditReportDO);
    }

    /**
     *
     * @param query 查询记录字典
     * @param loan  贷款url字典
     * @param creditCard 信用卡url字典
     * @param basic 基本信息url字典
     * @param creditReportUrl 征信报告url
     * @param creditReportDO 征信报告对象用来报错返回的响应的
     * @param storageMap 存储结果 用来重试去除已经解析好了的
     * @param executor 线程池
     * @return 征信报告结果
     */
    @SneakyThrows
    public Map<String,Object> createCreditReport(DictDataRespDTO query,
                                   DictDataRespDTO loan,
                                   DictDataRespDTO creditCard,
                                   DictDataRespDTO basic,
                                   String creditReportUrl,
                                   CreditReportDO creditReportDO,
                                   Map<String, String> storageMap,
                                   ExecutorService executor) {

        Map<String, Object> map = new HashMap<>();
        Date date = new Date();
        log.info("异步大模型解析征信报告，开始时间：{}", DateUtil.formatDateTime(new Date()));
        List<CompletableFuture<Void>> futures = new ArrayList<>();

        if (!storageMap.containsKey(KEY_MODEL_LOAN)) {
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
                // 這裡的程式碼會在執行緒池中執行
                // 假設 CreditReportThreadsPost 是一個 Callable<String>
                CreditReportThreadsPost task = new CreditReportThreadsPost(loan.getValue() + "?input_info=" + creditReportUrl + "&app_id=" + ModelAnalysisDictEnum.APP_ID.getCode());
                try {
                    return task.call(); // 執行任務
                } catch (Exception e) {
                    throw new ServerException(-1,"正在处理中，请稍后重试");
                }
            }, executor).thenAccept(modelLoan -> {
                // 這個區塊會在上面任務成功後執行
                map.put(KEY_MODEL_LOAN, modelLoan);
                creditReportDO.setNonCyclic(modelLoan);
            });
            futures.add(future);
        }

        if (!storageMap.containsKey(KEY_MODEL_CREDIT_CARD)) {
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
                CreditReportThreadsPost task = new CreditReportThreadsPost(creditCard.getValue()+"?input_info="+creditReportUrl+"&app_id="+ModelAnalysisDictEnum.APP_ID.getCode());
                try {
                    return task.call();
                } catch (Exception e) {
                    throw new ServerException(-1,"正在处理中，请稍后重试");
                }
            }, executor).thenAccept(modelCreditCard -> {
                creditReportDO.setCyclicOne(modelCreditCard);
                map.put(KEY_MODEL_CREDIT_CARD, modelCreditCard);
            });
            futures.add(future);
        }

        if (!storageMap.containsKey(KEY_QUERY_RECORD)) {
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
                CreditReportThreadsPost task = new CreditReportThreadsPost(query.getValue()+"?input_url="+creditReportUrl+"&app_id="+ModelAnalysisDictEnum.APP_ID.getCode());
                try {
                    return task.call();
                } catch (Exception e) {
                    throw new ServerException(-1,"正在处理中，请稍后重试");
                }
            }, executor).thenAccept(modelQuery -> {
                map.put(KEY_QUERY_RECORD, modelQuery);
                creditReportDO.setCyclicTow(modelQuery);
            });
            futures.add(future);
        }

        if (!storageMap.containsKey(KEY_BASIC)) {
            CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
                CreditReportThreadsPost task = new CreditReportThreadsPost(basic.getValue()+"?input_url="+creditReportUrl+"&app_id="+ModelAnalysisDictEnum.APP_ID.getCode());
                try {
                    return task.call();
                } catch (Exception e) {
                    throw new ServerException(-1,"正在处理中，请稍后重试");
                }
            }, executor).thenAccept(modelObject -> {
                creditReportDO.setBasic(modelObject);
                map.put(KEY_BASIC, modelObject);
            });
            futures.add(future);
        }

        // 等待所有已提交的非同步任務完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
        log.info("异步大模型解析征信报告，结束时间：{}", DateUtil.formatDateTime(new Date()));
        log.info("大模型计算时间:{}秒",DateUtil.between(date, new Date(), cn.hutool.core.date.DateUnit.SECOND));
        return map;
    }





}